#include "iAP2_AppStub.h"
#include "carplayExt.h"
#include "CarPlayInterface.h"
#include "AudioUtils.h"

#include "util/CStrTool.h"
#include "CIpodConfig.h"


static UserInterfaceDelegate	userDelegate;
static ICarplayCallbacks *      globalCallbacks = nullptr;
AudioStreamRef* inStreamRef = NULL;

SdCarplay::SdCarplay(ICarplayCallbacks* pcbs) {
    mCallbacks = pcbs;
    globalCallbacks = mCallbacks;
    mAirPlayModeState = nullptr;
    mCarplayState = CarplayStateInit;
    mType = CARPLAY_WL;
}

SdCarplay::~SdCarplay() {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks = nullptr;
	}

}

void carplaySessionStart() {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->carplaySessionStart();
	}
}

int iap2WriteData(const char* buf, int len) {
	if(globalCallbacks != nullptr )
	{
		char temp [ len ];
		memset(temp,0,len);
		memcpy(temp,buf,len);
		return globalCallbacks->iap2WriteData(temp, len);
	}
	return 0;
}

void carplaySessionStop() {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->carplaySessionStop();
	}
}
int switchUsbModeCB(int mode) {
	if(globalCallbacks != nullptr )
	{
		return globalCallbacks->switchUsbModeCB(UsbHost);
	}
	return 0;
}

void carplayExitCB() {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->carplayExitCB();
	}
}
void returnNativeUICB() {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->returnNativeUICB();
	}

}

void modesChangeCB(int arg_screen,
        int arg_permScreen,
        int arg_audio,
        int arg_permAudio,
        int arg_speechEntity,
        int arg_speechMode,
        int arg_phoneCall,
        int arg_turnByTurn){
	if(globalCallbacks != nullptr )
	{
		CarPlayModeState modeState;
		modeState.phoneCall = arg_phoneCall;
		modeState.screen = arg_permScreen;
		modeState.mainAudio = arg_audio;
		globalCallbacks->modesChangeCB(&modeState);
	}
}

void disableBluetoothCB() {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->disableBluetoothCB();
	}
}

void carplayDuckAudioCB(double inDurationSecs, double inVolume) {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->caplayDuckAudioCB(inDurationSecs, inVolume);
	}
}
void carplayUnduckAudioCB(double inDurationSecs) {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->caplayUnduckAudioCB(inDurationSecs);
	}

}


void carplayAudioStartCB(int handle, int type, int rate, int bits, int channels, void*  inStream) {
	if(globalCallbacks != nullptr )
	{
		UserAudioStreamType newType = AudioStreamMedia;
		inStreamRef = (AudioStreamRef*) inStream;
		globalCallbacks->carplayAudioStartCB(handle, newType, rate, bits, channels);
	}

}

void carplayAudioStopCB(int handle, int type) {
	if(globalCallbacks != nullptr )
	{
		UserAudioStreamType newType = AudioStreamMedia;
		globalCallbacks->carplayAudioStopCB(handle, newType);
	}
}

int carplayVideoStartCB() {
	if(globalCallbacks != nullptr )
	{
		return globalCallbacks->carplayVideoStartCB();
	}
	return 0;
}

void carplayVideoStopCB() {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->carplayVideoStopCB();
	}
}

int carplayVideoDataProcCB(const uint8_t* buf, int len) {
	if(globalCallbacks != nullptr )
	{
		return globalCallbacks->carplayVideoDataProcCB((const char *)buf, len);
	}
	return 0;
}

void NotifyDeviceNameCB(const char* name, int name_len) {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->NotifyDeviceNameCB(name, name_len);
	}
}

void appleTimeUpdateCB(long long time) {
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->appleTimeUpdateCB(time);
	}

}

void appleLanguageUpdateCB(const char* lang) {

	if(globalCallbacks != nullptr )
	{
		globalCallbacks->appleLanguageUpdateCB(lang);
	}

}
void appleCallStateUpdateCB(const char* remoteId,
                            const char* displayName,
                            int status,
                            int direction,
                            const char* uuid,
                            const char* addrBookId,
                            const char* label,
                            int service)
{
	if(globalCallbacks != nullptr )
	{
		globalCallbacks->appleCallStateUpdateCB(remoteId,displayName,status,direction,uuid,addrBookId,label,service);
	}

}

char* mfi_i2c_dev_nameCB() {

    return "/dev/i2c-2";
}


int SdCarplay::init() {
	UserInterfaceDelegateInit( &userDelegate );
//	userDelegate.useriAP2LinkStatus_f = _OnAirPlayiAP2LinkStatus;
	userDelegate.useriAP2WriteData_f = iap2WriteData;
	userDelegate.userCarPlaySessionStart_f = carplaySessionStart;
	userDelegate.userCarPlaySessionStop_f = carplaySessionStop;
	userDelegate.userSwitchUsbMode_f = switchUsbModeCB;
	userDelegate.userDeviceTimeUpdate_f = appleTimeUpdateCB;
	userDelegate.userDeviceLanguageUpdate_f = appleLanguageUpdateCB;
	userDelegate.userCallStateUpdate_f = appleCallStateUpdateCB;
	userDelegate.userDeviceInformationUpdate_f = NotifyDeviceNameCB;
	userDelegate.userAirPlaySessionEnd_f = carplayExitCB;
	userDelegate.userRequestUI_f = returnNativeUICB;
	userDelegate.userModesChanged_f = modesChangeCB;
	userDelegate.userDisableBluetooth_f = disableBluetoothCB;
	userDelegate.userAirPlayDuckAudio_f = carplayDuckAudioCB;
	userDelegate.userAirPlayUnduckAudio_f = carplayUnduckAudioCB;
	userDelegate.userAirPlayAudioStreamStart_f = carplayAudioStartCB;
	userDelegate.userAirPlayAudioStreamStop_f = carplayAudioStopCB;
	userDelegate.userAirPlayScreenStreamStart_f = carplayVideoStartCB;
	userDelegate.userAirPlayScreenStreamStop_f = carplayVideoStopCB;
	userDelegate.userAirPlayScreenStreamData_f = carplayVideoDataProcCB;
	UserInterfaceSetDelegate( &userDelegate );

    char** result = (char**) malloc(30 * sizeof(char*));
    int len = CIpodConfig::getDevicePlatformParam(result);
    startCarplay(len,result);

    for (int i = 0; i < len; i++) {
        free(result[i]);
    }
    free(result);

    return 0;
}

int SdCarplay::start(LinkType type,InitialMode initialmode) {
    int iAPConnetType = -1;
    int vendorId = 0;
    int productId =0 ;
    int argSame = 0 ;
    switch (type) {
        case CARPLAY:
            iAPConnetType = 1;
            break;
        case CARPLAY_WL:
            iAPConnetType = 3;
            break;
        default:
            iAPConnetType = 0;
            break;
    }

    char buffer1[10];
    IPODDeviceInformation* information = CIpodConfig::getIPODDeviceInformation();
    if (information->wifi_ssid != NULL) {
        sendWifiInformation(information->wifi_ssid, information->wifi_passwd, information->wifi_securityType, information->wifi_channel);
    }

    char** result = (char**) malloc(30 * sizeof(char*));
    int len = CIpodConfig::getDevicePlatformParam(result);
    setPlatformParam(len, result);
    free(result);

    sendSetup(iAPConnetType,vendorId,productId,NULL,argSame);
    return 0;

}

void SdCarplay::setValue(const char* key, int value, bool save) {
    CIpodConfig::setDeviceInfomationValue(key, value);
}

void SdCarplay::setValue(const char* key, const char* value, bool save) {
    CIpodConfig::setDeviceInfomationValue(key, value);
}

int SdCarplay::getIntValue(const char* key) {
    return 0;
}

const char* SdCarplay::getStringValue(const char* key) {

    const char* str="none";
    return str;
}

SdCarplay::CarplayState SdCarplay::getCarplayState(void) {
    return this->mCarplayState;
}



void SdCarplay::stop() {
    sendEnd();
}

void SdCarplay::setCarplayAudioMode(bool release) {

}

/* *
 * @brief 获取carplay送过来的音频数据,然后送到声卡播放
 * @param       handle 该路音频流操作句柄
 * @param       buffer 数据缓存
 * @param       len 数据缓存大小
 * @param       frames  音频数据帧大小 frames = len / (bits / 8 * channels)
 * @timestamp   timestamp 播放时间戳
 * */
void SdCarplay::playStream(int handle, void *buffer, int len, int frames, unsigned long long timestamp) {
    if (inStreamRef != NULL) {
        AudioStreamOutputProc(buffer,  len,  frames, timestamp, inStreamRef);
    } else {

    }
}

void SdCarplay::recordStream(int handle, void *buffer, int len, int frames, unsigned long long timestamp) {
    if (inStreamRef != NULL) {
        AudioStreamInputProc(handle,  buffer, len,  frames,  timestamp, inStreamRef);
    }
}


#if 0
CarplayState SdCarplay::getCarplayState(void) {

    //return this->mCarplayState;
}
#endif

void SdCarplay::sendSingleTouchscreen(unsigned short x, unsigned short y, bool pressed) {
    sendTouchScreenUpdate(pressed,x,y);
}

//发送多点触摸坐标 idx0=0表示第一个点, idx1= 1表示第二个点
void SdCarplay::sendMulPtrTouchscreen(unsigned char idx0, unsigned short x0, unsigned short y0, bool pressed0,
                                      unsigned char idx1, unsigned short x1, unsigned short y1, bool pressed1) {

}

//发送媒体按键
void SdCarplay::sendMediaButton(SdCarplay::MediaButton button, bool pressed) {

    uint16_t index = 0;

    if (pressed == 1) {

        switch (button) {
            case MediaNone:
                index = 0;
                break;
            case MediaPlay:
                index = 1;
                break;
            case MediaPause:
                index = 2;
                break;
            case MediaNext:
                index = 3;
                break;
            case MediaPrevious:
                index = 4;
                break;
            default:
            break;
        }
    }

    sendMediaButtonUpdate(index);
}

//发送knob的信息
void SdCarplay::sendKnobUpdate(char       selectButtonPressed,
                               char    homeButtonPressed,
                               char    backButtonPressed,
                               double  x,
                               double  y,
                               char    wheelPositionRelative) {

    KnobUpdate(selectButtonPressed, homeButtonPressed, backButtonPressed, x, y, wheelPositionRelative);
}

//强制手机发送关键帧
void SdCarplay::forceKeyFrame(void) {
    sendForceKeyFrame();
}

void SdCarplay::sendTelephoneButton(TelButton button, bool pressed) {
    int tele_key =0 ;
    if (button == CallAccept && pressed == 1) {
        tele_key = 1;
    }
    else if (button == CallDrop && pressed ==1) {
        tele_key = 3;
    }
    else if (pressed == 0) {
        tele_key = 0;
    }
    sendTelephonyUpdate(tele_key);
}

void SdCarplay::sendSiriButton(bool pressed) {

    int siri_action;
    if (pressed == 0) {
        siri_action = 2;
    }
    else {
        siri_action = 3;
    }
    sendRequestSiriAction(siri_action);
}


void SdCarplay::requestUI(AppleUIApp app) {
    char const* strmap="maps:";
    char const* strphone="mobilephone:";
    char const* strnowplaying="nowplaying:";
    char const* strmusice="music:";
    char const* strSend = NULL;

    switch (app) {
        case AppleUIAppMap:
            strSend = strmap;
            break;
        case AppleUIAppPhone:
            strSend = strphone;
            break;
        case AppleUIAppNowPlaying:
            strSend = strnowplaying;
            break;
        case AppleUIAppMusic:
            strSend = strmusice;
            break;
        case AppleUIAppNomal:
            sendRequestUi();
            break;
        default:
            break;
    }

    if (app != AppleUIAppNomal) {
        sendRequestUiWithUrl(strSend);
    }
}

void SdCarplay::setNightMode(bool enter) {
    sendSetNightMode(enter);
}

void SdCarplay::changeModes(CarplayTransferType         inScreenType,
                            CarplayTransferPriority     inScreenPriority,
                            CarplayConstraint           inScreenTake,
                            CarplayConstraint           inScreenBorrow,
                            CarplayTransferType         inAudioType,
                            CarplayTransferPriority     inAudioPriority,
                            CarplayConstraint           inAudioTake,
                            CarplayConstraint           inAudioBorrow,
                            CarplayTriState             inPhone,
                            CarplaySpeechMode           inSpeech,
                            CarplayTriState             inTurnByTurn) {
    // TODO:  还差 ScreenBorrowID , AudioBorrowID
    sendChangeModes("", inScreenType, inScreenPriority, inScreenTake, inScreenBorrow, "", inAudioType,
                    inAudioPriority, inAudioTake, inAudioBorrow, inPhone, inSpeech, inTurnByTurn);
}


void SdCarplay::setBtAddr(char mac[6]) {
    setBtMacAddr(mac);
}

int SdCarplay::readIap2DataProc(char* buf, int len) {
    int ret = -1;
    ret = sendRfcommData(buf,len);
    return ret;
}
